import { defineStore } from "pinia"
import { createIndexedDB } from "./create"
const readyTicks = []
export const useIndexedDBStore = defineStore("indexedDB", {
	state() {
		return {
			database: null,
		}
	},
	actions: {
		async init() {
			if (this.database) {
				return
			}
			this.database = await createIndexedDB()
			readyTicks.forEach(({ resolve }) => {
				if (this.database) {
					resolve()
				}
			})
		},
		set(tableName, value) {
			if (!this.database) {
				return new Promise((resolve, reject) => {
					readyTicks.push({
						resolve: async () => {
							try {
								await this.set(tableName, value)
								resolve()
							} catch (error) {
								reject(error)
							}
						},
					})
				})
			}
			let request
			try {
				const transaction = this.database.transaction([tableName], "readwrite")
				const objectStore = transaction.objectStore(tableName)
				request = objectStore.put(value)
			} catch (error) {
				return Promise.reject(error)
			}
			return new Promise((resolve, reject) => {
				request.onsuccess = () => {
					resolve()
				}
				request.onerror = error => {
					reject(error)
				}
			})
		},
		get(tableName, key) {
			if (!key) return Promise.reject("Key is required")
			if (!this.database) {
				return new Promise((resolve, reject) => {
					readyTicks.push({
						resolve: async () => {
							try {
								resolve(await this.get(tableName, key))
							} catch (error) {
								reject(error)
							}
						},
					})
				})
			}
			let request
			try {
				const transaction = this.database.transaction([tableName])
				const objectStore = transaction.objectStore(tableName)
				request = objectStore.get(key)
			} catch (error) {
				return Promise.reject(error)
			}
			return new Promise((resolve, reject) => {
				request.onsuccess = () => {
					resolve(request.result)
				}
				request.onerror = error => {
					reject(error)
				}
			})
		},
		querySelect(tableName, col, value) {
			if (!this.database) {
				return new Promise((resolve, reject) => {
					readyTicks.push({
						resolve: async () => {
							try {
								resolve(await this.querySelect(tableName, col, value))
							} catch (error) {
								reject(error)
							}
						},
					})
				})
			}
			let request
			try {
				const transaction = this.database.transaction([tableName])
				const objectStore = transaction.objectStore(tableName)
				request = objectStore.index(col).get(value)
			} catch (error) {
				return Promise.reject(error)
			}
			return new Promise((resolve, reject) => {
				request.onsuccess = event => {
					resolve(event.target.result)
				}
				request.onerror = error => {
					reject(error)
				}
			})
		},
		select(tableName, col, callback = () => {}) {
			if (!this.database) {
				return new Promise((resolve, reject) => {
					readyTicks.push({
						resolve: async () => {
							try {
								await this.select(tableName, col, callback)
								resolve()
							} catch (error) {
								reject(error)
							}
						},
					})
				})
			}
			let request
			try {
				const transaction = this.database.transaction([tableName])
				const objectStore = transaction.objectStore(tableName)
				request = objectStore.index(col).openCursor()
			} catch (error) {
				return Promise.reject(error)
			}
			return new Promise(resolve => {
				request.onsuccess = async () => {
					if (request.result) {
						await callback(request.result.value)
						request.result.continue()
					} else {
						resolve()
					}
				}
			})
		},
		getAll(tableName) {
			if (!this.database) {
				return new Promise((resolve, reject) => {
					readyTicks.push({
						resolve: async () => {
							try {
								resolve(await this.getAll(tableName))
							} catch (error) {
								reject(error)
							}
						},
					})
				})
			}
			let request
			try {
				const transaction = this.database.transaction([tableName])
				const objectStore = transaction.objectStore(tableName)
				request = objectStore.getAll()
			} catch (error) {
				return Promise.reject(error)
			}
			return new Promise((resolve, reject) => {
				request.onsuccess = () => {
					resolve(request.result)
				}
				request.onerror = error => {
					reject(error)
				}
			})
		},
		delete(tableName, key) {
			if (!key) return Promise.reject("Key is required")
			if (!this.database) {
				return new Promise((resolve, reject) => {
					readyTicks.push({
						resolve: async () => {
							try {
								await this.delete(tableName, key)
								resolve()
							} catch (error) {
								reject(error)
							}
						},
					})
				})
			}
			let request
			try {
				const transaction = this.database.transaction([tableName], "readwrite")
				const objectStore = transaction.objectStore(tableName)
				request = objectStore.delete(key)
			} catch (error) {
				return Promise.reject(error)
			}
			return new Promise((resolve, reject) => {
				request.onsuccess = () => {
					resolve()
				}
				request.onerror = error => {
					reject(error)
				}
			})
		},
		clear(tableName) {
			if (!this.database) {
				return new Promise((resolve, reject) => {
					readyTicks.push({
						resolve: async () => {
							try {
								await this.clear(tableName)
								resolve()
							} catch (error) {
								reject(error)
							}
						},
					})
				})
			}
			let request
			try {
				const transaction = this.database.transaction([tableName], "readwrite")
				const objectStore = transaction.objectStore(tableName)
				request = objectStore.clear()
			} catch (error) {
				return Promise.reject(error)
			}
			return new Promise((resolve, reject) => {
				request.onsuccess = () => {
					resolve()
				}
				request.onerror = error => {
					reject(error)
				}
			})
		},
		put(tableName, value) {
			if (!this.database) {
				return new Promise((resolve, reject) => {
					readyTicks.push({
						resolve: async () => {
							try {
								await this.put(tableName, value)
								resolve()
							} catch (error) {
								reject(error)
							}
						},
					})
				})
			}
			let request
			try {
				const transaction = this.database.transaction([tableName], "readwrite")
				const objectStore = transaction.objectStore(tableName)
				request = objectStore.put(value)
			} catch (error) {
				return Promise.reject(error)
			}
			return new Promise((resolve, reject) => {
				request.onsuccess = () => {
					resolve()
				}
				request.onerror = error => {
					reject(error)
				}
			})
		},
	},
})
